package se.perp.c4.net;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
import se.perp.c4.control.iface.IConnectionListener;

public class Connection implements IConnection, IFeederErrorListener {

    private Socket socket;
    private final Feeder feeder;
    private static ServerSocket serverSocket = null;
    private boolean isServer = false;
    private IConnectionListener listener = null;
    private static Logger logger = Logger.getLogger(Connection.class.getName());

    public void feederError() {
        if (listener != null) {
            listener.connectionIsDead();
        }
    }
    
    public void setConnectionListener(IConnectionListener l) {
        listener = l;
    }

    private static void forceCloseServerSocket() {
        if (serverSocket != null) {
            try {
                serverSocket.close();
            } catch (IOException ioe) {
                // whatever
            }
            serverSocket = null;
        }
    }

    private Connection(Socket socket, boolean isServer) throws IOException {
        this.socket = socket;
        this.isServer = isServer;

        DataOutputStream out = new DataOutputStream(socket.getOutputStream());
        DataInputStream in = new DataInputStream(socket.getInputStream());
        
        feeder = new Feeder(in, out, this);
    }

    public static Connection newServer(int port) throws IOException {
        forceCloseServerSocket();
        serverSocket = new ServerSocket(port);
        Socket s = serverSocket.accept();
        return new Connection(s, true);
    }

    public static Connection newClient(String host, int port) throws IOException {
        forceCloseServerSocket();
        Socket s = new Socket(host, port);
        return new Connection(s, false);
    }

    public boolean isServer() {
        return isServer;
    }

    public void sendMessage(Message m) {
        feeder.queueMessage(m);
    }

    public Message waitForNextMessage() {
        Message m = null;
        while (m == null) {
            m = feeder.getNextMessage();
            if (m == null) {
                try {
                    Thread.sleep(250);
                } catch (InterruptedException ie) {
                    // do nothing
                }
            } else {
                feeder.removeFirstIncoming();
            }
        }
        return m;
    }

    public void close() {
        try {
            feeder.terminate();
            socket.close();
            if (serverSocket != null) {
                serverSocket.close();
                serverSocket = null;
            }
        } catch (IOException ioe) {
            logger.log(Level.WARNING, ioe.getMessage(), ioe);
        }
    }
}
